/*
-----------------------------------------------------------------------------
This source file is part of Labor3D
(Labor 3D Graphics Engine)

Copyright (c) 2009-2020 Rock Mao
* creator : Rock Mao
* created : 2009-6-27   22:29
* filename: LaborD3D10Device.h
-----------------------------------------------------------------------------
*/

#ifndef __LABORD3D10DEVICE_H__
#define __LABORD3D10DEVICE_H__
#include "LaborD3D10Def.h"
#include "LaborD3D10Headers.h"


NAMESPACE_LABOR3D_BEGIN

class CLD3D10Device
{
private:
	ID3D10Device * m_pD3D10Device;

public:
	CLD3D10Device();
	~CLD3D10Device();
	CLD3D10Device(ID3D10Device * device);

	inline ID3D10Device * operator->() const
	{
		assert(m_pD3D10Device); 
		if (D3D_NO_EXCEPTION != mExceptionsErrorLevel)
		{
			clearStoredErrorMessages();
		}
		return m_pD3D10Device;
	}

	inline const void clearStoredErrorMessages(  ) const
	{
		if (m_pD3D10Device && D3D_NO_EXCEPTION != mExceptionsErrorLevel)
		{
			ID3D10InfoQueue * pInfoQueue = NULL; 
			HRESULT hr = m_pD3D10Device->QueryInterface(__uuidof(ID3D10InfoQueue), (LPVOID*)&pInfoQueue);
			if (SUCCEEDED(hr))
			{
				pInfoQueue->ClearStoredMessages();
			}
		}
	}

	ID3D10Device * operator=(ID3D10Device * device);
	const bool isNull();
	const string getErrorDescription(const HRESULT hr = NO_ERROR) const;

	inline const bool isError(  ) const
	{
		if (D3D_NO_EXCEPTION == mExceptionsErrorLevel)
		{
			return  false;
		}

		return _getErrorsFromQueue();
	}

	const bool _getErrorsFromQueue() const
	{
		ID3D10InfoQueue * pInfoQueue = NULL; 
		HRESULT hr = m_pD3D10Device->QueryInterface(__uuidof(ID3D10InfoQueue), (LPVOID*)&pInfoQueue);
		if (SUCCEEDED(hr))
		{
			unsigned int numStoredMessages = (unsigned int )pInfoQueue->GetNumStoredMessages();

			if (D3D_INFO == mExceptionsErrorLevel && numStoredMessages > 0)
			{
				// if D3D_INFO we don't need to loop if the numStoredMessages > 0
				return true;
			}
			for (unsigned int i = 0 ; i < numStoredMessages ; i++ )
			{
				// Get the size of the message
				SIZE_T messageLength = 0;
				hr = pInfoQueue->GetMessage(i, NULL, &messageLength);
				// Allocate space and get the message
				D3D10_MESSAGE * pMessage = (D3D10_MESSAGE*)malloc(messageLength);
				hr = pInfoQueue->GetMessage(i, pMessage, &messageLength);

				bool res = false;
				switch(pMessage->Severity)
				{
				case D3D10_MESSAGE_SEVERITY_CORRUPTION:
					if (D3D_CORRUPTION == mExceptionsErrorLevel)
					{
						res = true;
					}
					break;
				case D3D10_MESSAGE_SEVERITY_ERROR:
					switch(mExceptionsErrorLevel)
					{
					case D3D_CORRUPTION :
					case D3D_ERROR:
						res = true;
					}
					break;
				case D3D10_MESSAGE_SEVERITY_WARNING:
					switch(mExceptionsErrorLevel)
					{
					case D3D_CORRUPTION :
					case D3D_ERROR:
					case D3D_WARNING:
						res = true;
					}
					break;
				}

				free(pMessage);
				if (res)
				{
					// we don't need to loop anymore...
					return true;
				}

			}

			return false;

		}
		else
		{
			return false;
		}
	}
	void release();
	ID3D10Device * get();

	enum eExceptionsErrorLevel
	{
		D3D_NO_EXCEPTION,
		D3D_CORRUPTION,
		D3D_ERROR,
		D3D_WARNING,
		D3D_INFO,
	};

	static eExceptionsErrorLevel mExceptionsErrorLevel;
	static void setExceptionsErrorLevel(const eExceptionsErrorLevel exceptionsErrorLevel);
	static const eExceptionsErrorLevel getExceptionsErrorLevel();

};

NAMESPACE_LABOR3D_END

#endif //__LABORD3D10DEVICE_H__